#include "RpcDcClient.h"
#include "SE_Exception.h"


//public
RpcDcClient::RpcDcClient() :
    RpcClient(),
    m_strWebSvcEndpoint(""),
    m_fIsSvcProtected(false),
    m_strCode("")
{ }

//public
RpcDcClient::RpcDcClient(__in std::string &svcAddress, __in std::string &webSvcEndpoint, __in std::string &dcSvcEndpoint) :
    RpcClient(svcAddress, dcSvcEndpoint),
    m_strWebSvcEndpoint(webSvcEndpoint),
    m_fIsSvcProtected(false),
    m_strCode("")
{ }

//public    
RpcDcClient::~RpcDcClient() {

    if (InqIsConnected()) {

        Disconnect();
    }

    if (InqIsBound()) {

        _Unbind();
    }

    m_fIsSvcProtected = false;

    m_strCode.clear();
}

//public
// virtual RpcClient::Connect
bool RpcDcClient::Connect() {

    RPC_STATUS  status      = S_OK;
    bool        fConnected  = false;


    // Create binding
    if (!_Bind()) {

        return false;
    }

    // Create client connection instance on server-side
    {
        // DO NOTHING
    }

    // Call remote function for connection probe
    if (!_ConnectionProbe()) {

        _Unbind();

        return false;
    }

    _SetIsConnected(true);

    // Carry out additional connection post initialization
    _ConnectionPost();

    return true;
}

//public
// virtual RpcClient::Disconnect
void RpcDcClient::Disconnect() {

    if (InqIsConnected()) {

        _SetIsConnected(false);
    }


    _SetIsConnected( false );

    m_fIsSvcProtected = false;

    m_strCode.clear();

    _Unbind();

    return;
}

//public
bool RpcDcClient::Configure(__in std::string &svcAddress, __in std::string &webSvcEndpoint, __in std::string &dcSvcEndpoint) {

    if (!InqIsBound()) {

        m_strSvcAddress = svcAddress;

        m_strSvcEndpoint = dcSvcEndpoint;
    }
    else {

        return false;
    }

    m_strWebSvcEndpoint = webSvcEndpoint;

    return true;
}

//public    
bool RpcDcClient::ExecuteRequest(__in long ioctl, __in long sizeIn, __in byte *buffIn, __in long sizeOut, __out byte *buffOut, __out long *pResultOut) {

    bool    fResult = false;
    byte   *buffInExt = NULL;
    long    sizeInExt = 0;


    *pResultOut = 0;

    if (!(InqIsBound() && InqIsConnected())) {

        return false;
    }

    if (InqIsSvcProtected() && m_strCode.length() >= eExtendSize) {

        return false;
    }

    sizeInExt = sizeIn + eExtendSize;

    if (sizeInExt <= 0 || sizeInExt < sizeIn) {

        _SetErrCode(ERROR_INCORRECT_SIZE);

        return false;
    }

    if (NULL == (buffInExt = (byte*)malloc(sizeInExt))) {

        _SetErrCode(ERROR_NOT_ENOUGH_MEMORY);

        return false;
    }

    memset(buffInExt, 0, sizeInExt);

    memcpy(buffInExt, buffIn, sizeIn);

    if (InqIsSvcProtected()) {

        strncpy_s( (char*)buffInExt + sizeIn,
                    eExtendSize,
                    m_strCode.c_str(),
                    m_strCode.length() );
    }

    try {
        
        sub_100305d0(m_hBinding, ioctl, sizeInExt, buffInExt, sizeOut, buffOut, pResultOut);

        fResult = true;
    }
    catch(SE_Exception e) {

        _SetErrCode( e.InqSE() );

        _SetErrInfo( __FUNCTION__ " : dc_inout() faulted with exception.");

        fResult = false;
    }

    if (buffInExt) {

        free(buffInExt);

        buffInExt = NULL;
    }

    return fResult;
}

//protected virtual RpcClient::_ConnectionProbe()
#pragma pack(push, 1)
bool RpcDcClient::_ConnectionProbe() {

    bool    fResult = false;
    
    struct {
        unsigned    u32_000_004;
    } tagCmdIn = { 0 };

    struct {
        unsigned    u32_000_004;
        unsigned    u32_004_008;
        unsigned    u32_008_00C;
        unsigned    u32_00C_010;
        byte        str_010_100[0xF0];
    } tagCmdOut = { 0 };

    long status = S_OK;


    try {

        sub_100305d0(m_hBinding, 0x4E39, sizeof(tagCmdIn), (byte*)&tagCmdIn, sizeof(tagCmdOut), (byte*)&tagCmdOut, &status);

        fResult = ( (tagCmdOut.u32_000_004 == 0x01020201) && 
                    (tagCmdOut.u32_004_008 == 0x08080909) && 
                    (tagCmdOut.u32_008_00C == 0x00000002)   );
    }
    catch(SE_Exception e) {

        _SetErrCode( e.InqSE() );

        _SetErrInfo( __FUNCTION__ " : dc_inout() faulted with exception.");

        fResult = false;
    }

    return fResult;
}
#pragma pack(pop)

//protected virtual RpcClient::_ConnectionPost
void RpcDcClient::_ConnectionPost() {
    
    RpcWebClient rpcWebCli;

    if (!(InqIsBound() && InqIsConnected())) {

        return;
    }

    rpcWebCli.Configure(m_strSvcAddress, m_strWebSvcEndpoint, RpcWebClient::eConnTypeView);

    if (rpcWebCli.Connect()) {

        if (rpcWebCli.InqIsSvcProtected()) {

            m_fIsSvcProtected = true;

            rpcWebCli.InqCode(m_strCode);
        }

        rpcWebCli.Disconnect();
    }

    return;
}

// public
bool RpcDcClient::InqIsSvcProtected() {

    return m_fIsSvcProtected;
}
    
// public
void RpcDcClient::InqCode(__out std::string &codeOut) {

    codeOut = m_strCode;
}